package com.yugao.fintech.antelope.mps.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yugao.fintech.antelope.mps.api.constatnts.ChannelCodeEnum;
import com.yugao.fintech.antelope.mps.api.constatnts.ChannelTypeEnum;
import com.yugao.fintech.antelope.mps.api.model.content.MsgContent;
import com.yugao.fintech.antelope.mps.api.model.content.template.TemplateVarData;
import com.yugao.fintech.antelope.mps.api.model.rqrs.MsgPushParam;
import com.yugao.fintech.antelope.mps.assembly.MsgHistoryAssembly;
import com.yugao.fintech.antelope.mps.core.parser.AbstractTemplateParser;
import com.yugao.fintech.antelope.mps.core.propcess.MsgPushProcess;
import com.yugao.fintech.antelope.mps.manager.MsgHistoryManager;
import com.yugao.fintech.antelope.mps.manager.MsgPushTaskManager;
import com.yugao.fintech.antelope.mps.manager.MsgTemplateManager;
import com.yugao.fintech.antelope.mps.model.entity.MsgHistory;
import com.yugao.fintech.antelope.mps.model.entity.MsgPushTask;
import com.yugao.fintech.antelope.mps.model.entity.MsgTemplate;
import com.yugao.fintech.antelope.mps.model.rqrs.history.HistoryPageReq;
import com.yugao.fintech.antelope.mps.model.rqrs.history.HistoryQueryResp;
import com.yugao.fintech.antelope.mps.service.MsgHistoryService;
import com.yugao.fintech.framework.assistant.utils.exception.Assert;
import com.yugao.fintech.framework.desensitization.annotations.FieldBindHandle;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MsgHistoryServiceImpl implements MsgHistoryService {
    @Autowired
    private MsgHistoryManager historyManager;
    @Autowired
    private MsgHistoryAssembly historyAssembly;
    @Autowired
    private MsgPushProcess pushProcess;
    @Autowired
    private MsgTemplateManager templateManager;
    @Autowired
    private MsgPushTaskManager pushTaskManager;

    /**
     * 分页查询 消息推送
     *
     * @return 返回分页数据
     */
    @Override
    @FieldBindHandle
    public IPage<HistoryQueryResp> pageHistory(HistoryPageReq req) {
        IPage<MsgHistory> historyPage = historyManager.pageHistory(req);
        if (historyPage.getRecords().isEmpty()) {
            return new Page<>();
        }
        Set<Long> taskIds = historyPage.getRecords().stream().map(MsgHistory::getTaskId)
                .collect(Collectors.toSet());
        taskIds.add(-1L);

        Map<Long, MsgPushTask> taskMap = pushTaskManager.listByIds(taskIds).stream()
                .collect(Collectors.toMap(MsgPushTask::getId, Function.identity(), (k1, k2) -> k1));

        Map<String, String> channelMap = Arrays.stream(ChannelCodeEnum.values())
                .collect(Collectors.toMap(ChannelCodeEnum::getCode, ChannelCodeEnum::getName));

        // 设置消息内容动态渲染
        List<HistoryQueryResp> respData = historyPage.getRecords().stream()
                .filter(e -> taskMap.containsKey(e.getTaskId()))
                .map(e -> {
                    MsgPushTask pushTask = taskMap.get(e.getTaskId());
                    HistoryQueryResp resp = getMsgHistoryQueryResp(e, pushTask);
                    resp.setChannelCode(e.getChannelCode());
                    resp.setChannelName(channelMap.get(e.getChannelCode()));
                    return resp;
                }).collect(Collectors.toList());

        Page<HistoryQueryResp> resp = new Page<>(historyPage.getCurrent(), historyPage.getSize(), historyPage.getTotal());
        resp.setRecords(respData);
        return resp;
    }

    private HistoryQueryResp getMsgHistoryQueryResp(MsgHistory history, MsgPushTask pushTask) {
        HistoryQueryResp resp = historyAssembly.toMsgHistoryQueryResp(history, pushTask);
        List<TemplateVarData> originalTemplateVar = history.getOriginalTemplateVar();
        ChannelTypeEnum channelTypeEnum = ChannelTypeEnum.ofByCode(history.getChannelType());
        // 获取模板数据
        MsgTemplate template = templateManager.getById(history.getTemplateId());
        if (Objects.isNull(template)) {
            resp.setMsgContent("生成发送内容失败, 模板 " + history.getTemplateId() + " 不存在");
            return resp;
        }

        AbstractTemplateParser templateConfig = AbstractTemplateParser
                .jsonToObj(originalTemplateVar, template, channelTypeEnum);
        resp.setMsgContent(templateConfig.evaluate());

        ChannelCodeEnum channelCodeEnum = ChannelCodeEnum.ofByCode(history.getChannelCode());
        resp.setChannelName(Optional.ofNullable(channelCodeEnum).map(ChannelCodeEnum::getName).orElse("未知"));
        return resp;
    }


    /**
     * 根据主键查询 消息推送
     *
     * @param id 主键
     * @return 返回记录，没有返回null
     */
    @Override
    @FieldBindHandle
    public HistoryQueryResp getById(Long id) {
        MsgHistory history = historyManager.getById(id);
        Assert.notNull(history, "未查询到推送记录");

        MsgPushTask pushTask = pushTaskManager.getById(history.getTaskId());
        Assert.notNull(pushTask, "未查询到关联的任务");

        return getMsgHistoryQueryResp(history, pushTask);
    }

    /**
     * 通过id删除 消息推送
     *
     * @param id 删除的主键
     * @return 返回影响行数
     */
    @Override
    public boolean deleteById(Long id) {
        return historyManager.removeById(id);
    }

    /**
     * 通过ids删除 消息推送
     *
     * @param ids 删除的主键
     * @return 返回影响行数
     */
    @Override
    public boolean deleteByIds(List<Long> ids) {
        return historyManager.removeByIds(ids);
    }

    @Override
    @FieldBindHandle
    public void rePush(Long id) throws Exception {
        MsgHistory history = historyManager.getById(id);
        Assert.notNull(history, "未查询到推送记录");

        MsgPushTask pushTask = pushTaskManager.getById(history.getTaskId());
        Assert.notNull(pushTask, "未查询到关联的任务");

        MsgPushParam msgPushParam = toMsgPushParam(history, pushTask);
        pushProcess.push(msgPushParam, String.valueOf(id));
    }

    private MsgPushParam toMsgPushParam(MsgHistory history, MsgPushTask pushTask) throws Exception {
        MsgPushParam pushParam = new MsgPushParam();
        StopWatch stopWatch = StopWatch.createStarted();
        MsgContent msgContent = new MsgContent();
        msgContent.addAllTplData(history.getOriginalTemplateVar())
                .setBizKey(history.getBizKey()).setBizType(history.getBizType())
                .setTaskCode(pushTask.getTaskCode()).setToUser(history.getToUser());

        pushParam.setHistoryId(history.getId());
        pushParam.setMsgContent(msgContent);
        log.info("toMsgPushReq time: {} ms", stopWatch.getTime(TimeUnit.MILLISECONDS));
        stopWatch.stop();
        return pushParam;
    }
}